﻿using System;
using System.Collections;
using System.Collections.Generic;

namespace LuaVM.Core
{
	/// <summary>
	/// Lua集合对象，定义这个类是为了让后续项目只需要引入LuaVM.Core这一个类库即可
	/// </summary>
	public class LuaTable
	{
		/// <summary>
		/// 根据字符串键取值与赋值
		/// </summary>
		/// <param name="field">字符串键</param>
		/// <returns>储存数值</returns>
		public object this[string field]
		{ 
			get
			{
				return ConvertForGet(m_table[field]);				
			}

			set
			{
				m_table[field] = ConvertForSet(value);
			}
		}

		/// <summary>
		/// 根据其它类型键取值与赋值
		/// </summary>
		/// <param name="field">其它类型键</param>
		/// <returns>储存数值</returns>
		public object this[object field]
		{
			get
			{
				return ConvertForGet(m_table[field]);
			}

			set
			{
				m_table[field] = ConvertForSet(value);
			}
		}

		/// <summary>
		/// 从Lua环境转化出来
		/// </summary>
		/// <param name="data">数据源</param>
		/// <returns>转化后的数据</returns>
		public static object ConvertForGet(object data)
		{
			if (data == null)
			{
				return null;
			}

			if (data.GetType() == typeof(LuaInterface.LuaTable))
			{
				data = new LuaTable(data as LuaInterface.LuaTable);
			}
			return data;
		}

		/// <summary>
		/// 向Lua环境中转化进去
		/// </summary>
		/// <param name="data">数据源</param>
		/// <returns>转化后的数据</returns>
		public static object ConvertForSet(object data)
		{
			if (data == null)
			{
				return null;
			}

			if (data.GetType() == typeof(LuaTable))
			{
				data = (data as LuaTable).Table;
			}

			return data;
		}

		/// <summary>
		/// 隐性LuaInterface.Lua对象
		/// </summary>
		public object Table => m_table;

		/// <summary>
		/// 返回所有键
		/// </summary>
		public ICollection Keys => m_table.Keys;

		/// <summary>
		/// 返回所有值
		/// </summary>
		public ICollection Values => m_table.Values;

		/// <summary>
		/// 对象是否合法
		/// </summary>
		public bool Valid => m_table != null;

		// 匿名对象的真实路径
		const string AnonymousPath = "B515A6FC94DD4D688A54937B98C60931";

		// 隐性LuaInterface.Lua对象
		private LuaInterface.LuaTable m_table = null;

		/// <summary>
		/// 私有构造函数，任何LuaTable对象都必须通过LuaTable.Create或LuaTable.Find创建
		/// </summary>
		/// <param name="table">隐性LuaInterface.Lua对象</param>
		private LuaTable(LuaInterface.LuaTable table)
		{
			m_table = table;
		}

		/// <summary>
		/// 清空当前表中的所有键值对
		/// </summary>
		public void Clear()
		{
			IDictionaryEnumerator em = m_table.GetEnumerator();
			while (em.MoveNext())
			{
				m_table[em.Key] = null;
			}
		}

		/// <summary>
		/// 创建新表
		/// </summary>
		/// <param name="interpreter">隐性LuaInterface.Lua对象</param>
		/// <param name="path">储存路径，如果为null则为匿名对象（匿名对象后续无法通过GetTable获取）</param>
		/// <returns>创建成功返回新建对象，失败返回null</returns>
		public static LuaTable Create(object interpreter, string path)
		{
			if (string.IsNullOrEmpty(path))
			{
				path = AnonymousPath;
			}

			LuaInterface.Lua lua = interpreter as LuaInterface.Lua;
			lua.NewTable(path);
			LuaInterface.LuaTable table = lua.GetTable(path);
			if (table == null)
			{
				return null;
			}

			return new LuaTable(table);
		}

		/// <summary>
		/// 寻找已存在的表
		/// </summary>
		/// <param name="interpreter">隐性LuaInterface.Lua对象</param>
		/// <param name="path">储存路径</param>
		/// <returns>表存在返回对象，失败返回null</returns>
		public static LuaTable Find(object interpreter, string path)
		{
			if (string.IsNullOrEmpty(path))
			{
				return null;
			}

			LuaInterface.Lua lua = interpreter as LuaInterface.Lua;
			LuaInterface.LuaTable table = lua.GetTable(path);
			if (table == null)
			{
				return null;
			}

			return new LuaTable(table);
		}

		/// <summary>
		/// 完整复制一个数组中所有的元素到LuaTable中，数组中不允许包含null对象
		/// </summary>
		/// <param name="array">数组对象</param>
		public void CopyArray(ICollection array)
		{
			if (array == null)
			{
				return;
			}

			foreach (object item in array)
			{
				if (item == null)
				{
					throw new Exception("Lua array cannot contain null elements.");
				}
			}

			int index = 0;
			foreach (object value in array)
			{
				index++; // Lua数组下表为1-n
				m_table[index] = value;
			}			
		}		

		/// <summary>
		/// 完整复制一个Enum定义中所有的名称和值
		/// </summary>
		/// <typeparam name="T">Enum类型</typeparam>
		/// <param name="ignoreCase">如果为true则为所有键名的小写格式额外复制一份值</param>
		public void CopyEnum<T>(bool ignoreCase = false)
		{
			string[] names = Enum.GetNames(typeof(T));
			Array values = Enum.GetValues(typeof(T));

			for (int i = 0; i < names.Length; i++)
			{
				string name = names[i];
				object value = values.GetValue(i);
				m_table[name] = value;

				if (ignoreCase)
				{
					m_table[name.ToLower()] = value;
				}				
			}
		}		

		/// <summary>
		/// 获得枚举器
		/// </summary>
		/// <returns>枚举器</returns>
		public IDictionaryEnumerator GetEnumerator()
		{
			return m_table.GetEnumerator();
		}		
	}	
}
